home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / System 7.0 Samples / Kibitz / AppleEvents.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-21  |  15.7 KB  |  585 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        Kibitz
  5. ** File:        AppleEvents.c
  6. ** Written by:  Keith Rollin
  7. **
  8. ** Copyright © 1990-1991 Apple Computer, Inc.
  9. ** All rights reserved.
  10. **
  11. ** This code is completely based on the great work done by Keith Rollin.
  12. ** All I did was to add more comments than _anybody_ would want, make some
  13. ** things a little more general, and to set the code up so the the custom
  14. ** events are handled in a separate file.
  15. */
  16.  
  17.  
  18.  
  19. /*****************************************************************************/
  20.  
  21.  
  22.  
  23. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  24. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  25. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  26.  
  27. #ifndef __GESTALTEQU__
  28. #include <GestaltEqu.h>
  29. #endif
  30.  
  31. #ifndef __UTILITIES__
  32. #include <Utilities.h>
  33. #endif
  34.  
  35.  
  36.  
  37. /*****************************************************************************/
  38.  
  39.  
  40.  
  41. #define rErrorAlert 129
  42. #define kTimeOutInTicks (60 * 30)    /* 30 second timeout. */
  43.  
  44.  
  45.  
  46. /*****************************************************************************/
  47.  
  48.  
  49.  
  50. struct triplets{
  51.     AEEventClass    theEventClass;
  52.     AEEventID        theEventID;
  53.     ProcPtr            theHandler;
  54. };
  55. typedef struct triplets triplets;
  56. static triplets keywordsToInstall[] = {
  57.     { kCoreEventClass,        kAEOpenApplication,        DoAEOpenApplication },
  58.     { kCoreEventClass,        kAEOpenDocuments,        DoAEOpenDocuments },
  59.     { kCoreEventClass,        kAEPrintDocuments,        DoAEPrintDocuments },
  60.     { kCoreEventClass,        kAEQuitApplication,        DoAEQuitApplication }
  61.         /* The above are the four required AppleEvents. */
  62. };
  63.  
  64. Boolean        gHasAppleEvents = false;
  65. Boolean        gHasPPCToolbox  = false;
  66.  
  67.  
  68.  
  69. /*****************************************************************************/
  70.  
  71.  
  72.  
  73. extern Boolean    gQuitApplication;
  74. extern Cursor    *gCurrentCursor;
  75. extern short    gPrintPage;
  76.  
  77.  
  78.  
  79. /*****************************************************************************/
  80. /*****************************************************************************/
  81.  
  82.  
  83.  
  84. /* DoHighLevelEvent
  85. **
  86. ** Simply calls AEProcessAppleEvent and reports any errors.
  87. ** AEProcessAppleEvent looks in its table of registered events and sees if
  88. ** the current event is registered.  If so, it calls the routine associated
  89. ** with that event.  In our case, we set that to DispatchAppleEvent.
  90. ** DispatchAppleEvent handles it in all cases.  DispatchAppleEvent uses the
  91. ** refCon to determine which AppleEvent it is doing, since it gets them all.
  92. */
  93.  
  94. #pragma segment AppleEvents
  95. void    DoHighLevelEvent(EventRecord *event)
  96. {
  97.     AEProcessAppleEvent(event);
  98. }
  99.  
  100.  
  101.  
  102. /*****************************************************************************/
  103.  
  104.  
  105.  
  106. /* GetTargetInfo
  107. **
  108. */
  109.  
  110. #pragma segment AppleEvents
  111. OSErr    GetTargetInfo(AEAddressDesc targetDesc, StringPtr zone,
  112.                       StringPtr machine, StringPtr application)
  113. {
  114.     ProcessSerialNumber targetPSN;
  115.     PortInfoRec            portInfo;
  116.     TargetID            theTargetID;
  117.     OSErr                err;
  118.  
  119.     zone[0]        = 0;
  120.     machine[0]     = 0;
  121.     application[0] = 0;
  122.     err = noErr;
  123.  
  124.     if (targetDesc.descriptorType == typeProcessSerialNumber) {
  125.         targetPSN = **(ProcessSerialNumber **)(targetDesc.dataHandle);
  126.         err = GetPortNameFromProcessSerialNumber(&portInfo.name, &targetPSN);
  127.         if (!err) pstrcpy(application, portInfo.name.name);
  128.         return(err);
  129.     }
  130.  
  131.     if (targetDesc.descriptorType == typeTargetID) {
  132.         theTargetID = **(TargetID **)(targetDesc.dataHandle);
  133.         switch (theTargetID.location.locationKindSelector) {
  134.             case ppcNoLocation:
  135.                 break;
  136.             case ppcNBPLocation:
  137.                 pstrcpy(zone,    theTargetID.location.u.nbpEntity.zoneStr);
  138.                 pstrcpy(machine, theTargetID.location.u.nbpEntity.objStr);
  139.                 break;
  140.             case ppcNBPTypeLocation:
  141.                 break;
  142.         }
  143.         pstrcpy(application, theTargetID.name.name);
  144.         return(noErr);
  145.     }
  146.  
  147.     return(errAEWrongDataType);
  148. }
  149.  
  150.  
  151.  
  152. /*****************************************************************************/
  153.  
  154.  
  155.  
  156. /* InitAppleEvents
  157. **
  158. ** Intialize our AppleEvent dispatcher table.  For every triplet of entries in
  159. ** keywordsToInstall, we make a call to AEInstallEventHandler().
  160. */
  161.  
  162. #pragma segment AppleEvents
  163. void    InitAppleEvents(void)
  164. {
  165.     OSErr    err;
  166.     long    result;
  167.     short    i;
  168.  
  169.     gHasPPCToolbox  = (Gestalt(gestaltPPCToolboxAttr, &result) ? false : result != 0);
  170.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &result) ? false : result != 0);
  171.  
  172.     if (gHasAppleEvents) {
  173.         for (i = 0; i < (sizeof(keywordsToInstall) / sizeof(triplets)); ++i) {
  174.             err = AEInstallEventHandler(
  175.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  176.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  177.                 keywordsToInstall[i].theHandler,    /* The AppleEvent handler. */
  178.                 0L,                                    /* Unused refcon.           */
  179.                 false                                /* Only for our app.       */
  180.             );
  181.  
  182.             if (err) {
  183.                 Alert(rErrorAlert, nil);
  184.                 return;
  185.             }
  186.         }
  187.     }
  188. }
  189.  
  190.  
  191.  
  192. /*****************************************************************************/
  193.  
  194.  
  195.  
  196. /* MakeTarget
  197. **
  198. ** Creates a TargetID.
  199. **
  200. ** If sendDirect is TRUE, the target is specified by setting a
  201. ** ProcessSerialNumber to kCurrentProcess.  This has the advantage of sending
  202. ** the message directly to ourselves, bypassing ePPC and gaining about a 10-15x
  203. ** speed improvement.  If sendDirect is FALSE, we see if we have the
  204. ** PPCToolBox.  If not, then we are forced to do a direct send.  If we do have
  205. ** the PPCToolbox, then we call PPCBrowser.  We then look at the reply, and
  206. ** factor in the mode we are going to use in AESend.  If that mode is
  207. ** kAEWaitReply and the user selected us as the target, we have to turn that
  208. ** into a direct send.  This is because the AppleEvent Manager will otherwise
  209. ** post the event as a high-level event.  However, we are busy waiting for a
  210. ** reply, not looking for events, so we'll hang.  We avoid this by forcing a
  211. ** direct send.
  212. */
  213.  
  214. #pragma segment AppleEvents
  215. OSErr    MakeTarget(AEAddressDesc *target, Boolean sendDirect, short replyMode,
  216.                    Str255 prompt, Str255 applListLabel,PPCFilterProcPtr portFilter)
  217. {
  218.     OSErr                    err;
  219.     ProcessSerialNumber     targetPSN;
  220.     ProcessSerialNumber     myPSN;
  221.     TargetID                theTargetID;
  222.     Boolean                    sendingToSelf;
  223.  
  224.     static LocationNameRec    location;
  225.     static PortInfoRec        portInfo;
  226.     static Boolean            defaultOK = false;
  227.  
  228.     err = noErr;    /* Make sure we do the code for the second main if. */
  229.  
  230.     target->dataHandle = nil;
  231.         /* Assume we will fail and nil this descriptor out. */
  232.  
  233.     if (!sendDirect) {
  234.         if (!gHasPPCToolbox)
  235.             sendDirect = true;    /* No tools to send with, so send direct. */
  236.  
  237.         else {        /* We are not sending to self. */
  238.                     /* sendDirect is false.           */
  239.             err = PPCBrowser(
  240.                 prompt,            /* Browse dialog box prompt.           */
  241.                 applListLabel,    /* The 'programs' list title.           */
  242.                 defaultOK,        /* Initially false.                       */
  243.                 &location,        /* Correct if defaultOK is true.       */
  244.                 &portInfo,        /* Correct if defaultOK is true.       */
  245.                 portFilter,        /* No port filtering.                   */
  246.                 nil                /* List ports of type 'PPCToolBox'.       */
  247.             );
  248.  
  249.             if (!err) {                    /* If user didn't cancel... */
  250.                 defaultOK = true;        /* Default to the same port next time. */
  251.                 if (replyMode == kAEWaitReply) {
  252.                     /* Sender wants a reply and will be waiting... */
  253.  
  254.                     sendingToSelf = false;
  255.                         /* Assume that we aren't sending to ourselves. */
  256.  
  257.                     if (!location.locationKindSelector) {
  258.                         /* Hey, we are sending to ourselves! */
  259.  
  260.                         err = GetProcessSerialNumberFromPortName(
  261.                                 &portInfo.name, &targetPSN);
  262.                         if (!err) {
  263.                             GetCurrentProcess(&myPSN);
  264.                             err = SameProcess(&targetPSN, &myPSN, &sendingToSelf);
  265.                         }
  266.                     }
  267.  
  268.                     if (sendingToSelf) sendDirect = true;
  269.  
  270.                 }
  271.             }
  272.         }
  273.     }
  274.  
  275.     if (!err) {
  276.         if (sendDirect) {
  277.             /* Finally, we get to the point... */
  278.  
  279.             targetPSN.highLongOfPSN = 0;
  280.             targetPSN.lowLongOfPSN = kCurrentProcess;
  281.                 /* Process serial # is equal to kCurrentProcess.  This
  282.                 ** bypasses ePPC and speeds up things considerably. */
  283.  
  284.             err = AECreateDesc(
  285.                 typeProcessSerialNumber,    /* Standard PSN descriptor type. */
  286.                 (Ptr)&targetPSN,            /* "No ePPC" process serial #.     */
  287.                 sizeof(targetPSN),            /* Size of data (2 longs).         */
  288.                 target                        /* Wherefore art thou desc.         */
  289.             );
  290.         }
  291.         else {
  292.             theTargetID.location = location;
  293.             theTargetID.name     = portInfo.name;
  294.                 /* The fields sessionID does not need to be filled in now.
  295.                 ** The sessionID is returned when you actually connect to
  296.                 ** a port.  You can then use the sessionID from that point
  297.                 ** on to improve speed.
  298.                 **
  299.                 ** You also don't need to fill in the recvrName field at this
  300.                 ** point.  This is filled in, again, when the session is
  301.                 ** actually established.
  302.                 **
  303.                 ** The amount of data for a non-us target is bigger.
  304.                 ** We need the whole dealie for our target, since
  305.                 ** it is out on the net somewhere. */
  306.  
  307.             err = AECreateDesc(
  308.                 typeTargetID,            /* Standard target descriptor type. */
  309.                 (Ptr)&theTargetID,        /* The data for the descriptor.        */
  310.                 sizeof(theTargetID),    /* Size of the data.                */
  311.                 target                    /* Wherefore art thou desc.            */
  312.             );
  313.         }
  314.     }
  315.     return (err);
  316. }
  317.  
  318.  
  319.  
  320. /*****************************************************************************/
  321.  
  322.  
  323.  
  324. /* MissedAnyParameters
  325. **
  326. ** Used to check for any unread required parameters. Returns true if we
  327. ** missed at least one.
  328. */
  329.  
  330. #pragma segment AppleEvents
  331. Boolean    MissedAnyParameters(AppleEvent message)
  332. {
  333.     OSErr        err;
  334.     DescType    ignoredActualType;
  335.     AEKeyword    missedKeyword;
  336.     Size        ignoredActualSize;
  337.     EventRecord    event;
  338.  
  339.     err = AEGetAttributePtr(    /* SEE IF PARAMETERS ARE ALL USED UP.          */
  340.         &message,                /* AppleEvent to check.                          */
  341.         keyMissedKeywordAttr,    /* Look for unread parameters.                  */
  342.         typeKeyword,            /* So we can see what type we missed, if any. */
  343.         &ignoredActualType,        /* What is would have been if not coerced.      */
  344.         (Ptr)&missedKeyword,    /* Data area.  (Keyword not handled.)          */
  345.         sizeof(missedKeyword),    /* Size of data area.                          */
  346.         &ignoredActualSize        /* Actual data size.                          */
  347.     );
  348.  
  349. /* No error means that we found some unused parameters. */
  350.  
  351.     if (err == noErr) {
  352.         event.message = *(long *) &ignoredActualType;
  353.         event.where = *(Point *) &missedKeyword;
  354.         err = errAEEventNotHandled;
  355.     }
  356.  
  357. /* errAEDescNotFound means that there are no more parameters.  If we get
  358. ** an error code other than that, flag it.
  359. */
  360.  
  361.     return(err != errAEDescNotFound);
  362. }
  363.  
  364.  
  365.  
  366. /*****************************************************************************/
  367. /*****************************************************************************/
  368.  
  369.  
  370.  
  371. #pragma segment AppleEvents
  372. pascal OSErr    DoAEOpenApplication(AppleEvent message, AppleEvent reply, long refcon)
  373. {
  374. #pragma unused (message, refcon)
  375.  
  376.     FileRecHndl    frHndl;
  377.     OSErr        err;
  378.  
  379.     gCurrentCursor = nil;
  380.         /* Force re-calc of cursor region and cursor to use. */
  381.  
  382.     err = AppNewDocument(&frHndl);
  383.     if (!err)
  384.         if (err = AppNewWindow(frHndl, nil))
  385.             AppDisposeDocument(frHndl);
  386.  
  387.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  388.         &reply,                    /* The AppleEvent.              */
  389.         keyReplyErr,            /* AEKeyword                 */
  390.         typeShortInteger,        /* Desired type.             */
  391.         (Ptr)&err,                /* Pointer to area for data. */ 
  392.         sizeof(short)            /* Size of data area.         */
  393.     );
  394.  
  395.     return(err);
  396. }
  397.  
  398.  
  399.  
  400. /*****************************************************************************/
  401.  
  402.  
  403.  
  404. #pragma segment AppleEvents
  405. pascal OSErr    DoAEOpenDocuments(AppleEvent message, AppleEvent reply, long refcon)
  406. {
  407. #pragma unused (refcon)
  408.  
  409.     OSErr        err;
  410.  
  411.     gCurrentCursor = nil;
  412.         /* Force re-calc of cursor region and cursor to use. */
  413.  
  414.     err = OpenDocEventHandler(message, reply, 0);
  415.  
  416.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  417.         &reply,                    /* The AppleEvent.              */
  418.         keyReplyErr,            /* AEKeyword                 */
  419.         typeShortInteger,        /* Desired type.             */
  420.         (Ptr)&err,                /* Pointer to area for data. */ 
  421.         sizeof(short)            /* Size of data area.         */
  422.     );
  423.  
  424.     return(err);
  425. }
  426.  
  427.  
  428.  
  429. /*****************************************************************************/
  430.  
  431.  
  432.  
  433. #pragma segment AppleEvents
  434. pascal OSErr    DoAEPrintDocuments(AppleEvent message, AppleEvent reply, long refcon)
  435. {
  436. #pragma unused (refcon)
  437.  
  438.     OSErr        err;
  439.     short        openMode;
  440.  
  441.     gCurrentCursor = nil;
  442.         /* Force re-calc of cursor region and cursor to use. */
  443.  
  444.     openMode = 1;
  445.     if (!AEInteractWithUser(kTimeOutInTicks, nil, (IdleProcPtr)MyIdleProc))
  446.         ++openMode;
  447.  
  448.     err = OpenDocEventHandler(message, reply, openMode);
  449.  
  450.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  451.         &reply,                    /* The AppleEvent.              */
  452.         keyReplyErr,            /* AEKeyword                 */
  453.         typeShortInteger,        /* Desired type.             */
  454.         (Ptr)&err,                /* Pointer to area for data. */ 
  455.         sizeof(short)            /* Size of data area.         */
  456.     );
  457.  
  458.     return(err);
  459. }
  460.  
  461.  
  462.  
  463. /*****************************************************************************/
  464.  
  465.  
  466.  
  467. #pragma segment AppleEvents
  468. pascal OSErr    DoAEQuitApplication(AppleEvent message, AppleEvent reply, long refcon)
  469. {
  470. #pragma unused (message, refcon)
  471.  
  472.     OSErr    err;
  473.  
  474.     gCurrentCursor = nil;
  475.         /* Force re-calc of cursor region and cursor to use. */
  476.  
  477.     gQuitApplication = true;
  478.  
  479.     err = noErr;
  480.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  481.         &reply,                    /* The AppleEvent.              */
  482.         keyReplyErr,            /* AEKeyword                 */
  483.         typeShortInteger,        /* Desired type.             */
  484.         (Ptr)&err,                /* Pointer to area for data. */ 
  485.         sizeof(short)            /* Size of data area.         */
  486.     );
  487.  
  488.     return(noErr);
  489. }
  490.  
  491.  
  492.  
  493. /*****************************************************************************/
  494.  
  495.  
  496.  
  497. /* OpenDocEventHandler
  498. **
  499. ** Called when we recieve an AppleEvent with an ID of "kAEOpenDocuments".
  500. ** This routine gets the direct parameter, parses it up into little FSSpecs,
  501. ** and opens each indicated file.  It also shows the technique to be used in
  502. ** determining if you are doing everything the AppleEvent record is telling
  503. ** you.  Parameters can be divided up into two groups: required and optional.
  504. ** Before executing an event, you must make sure that you've read all the
  505. ** required events.  This is done by making an "any more?" call to the
  506. ** AppleEvent manager.
  507. */
  508.  
  509. #pragma segment AppleEvents
  510. OSErr    OpenDocEventHandler(AppleEvent message, AppleEvent reply, short mode)
  511. {
  512. #pragma unused (reply)
  513.  
  514.     OSErr        err;
  515.     OSErr        err2;
  516.     AEDesc        theDesc;
  517.     FSSpec        theFSS;
  518.     short        loop;
  519.     long        numFilesToOpen;
  520.     AEKeyword    ignoredKeyWord;
  521.     DescType    ignoredType;
  522.     Size        ignoredSize;
  523.     FileRecHndl    frHndl;
  524.     WindowPtr    docWindow;
  525.  
  526.     theDesc.dataHandle = nil;
  527.         /* Make sure disposing of the descriptors is okay in all cases.
  528.         ** This will not be necessary after 7.0b3, since the calls that
  529.         ** attempt to create the descriptors will nil automatically
  530.         ** upon failure. */
  531.  
  532.     if (err = AEGetParamDesc(&message, keyDirectObject, typeAEList, &theDesc))
  533.         return(err);
  534.  
  535.     if (!MissedAnyParameters(message)) {
  536.  
  537. /* Got all the parameters we need.  Now, go through the direct object,
  538. ** see what type it is, and parse it up. */
  539.  
  540.         err = AECountItems(&theDesc, &numFilesToOpen);
  541.         if (!err) {
  542.             /* We have numFilesToOpen that need opening, as either a window
  543.             ** or to be printed.  Go to it... */
  544.  
  545.             for (loop = 1; ((loop <= numFilesToOpen) && (!err)); ++loop) {
  546.                 err = AEGetNthPtr(        /* GET NEXT IN THE LIST...         */
  547.                     &theDesc,            /* List of file names.             */
  548.                     loop,                /* Item # in the list.             */
  549.                     typeFSS,            /* Item is of type FSSpec.         */
  550.                     &ignoredKeyWord,    /* Returned keyword -- we know.  */
  551.                     &ignoredType,        /* Returned type -- we know.     */
  552.                     (Ptr)&theFSS,        /* Where to put the FSSpec info. */
  553.                     sizeof(theFSS),        /* Size of the FSSpec info.         */
  554.                     &ignoredSize        /* Actual size -- we know.         */
  555.                 );
  556.                 if (err) break;
  557.  
  558.                 err = AppOpenDocument(&frHndl, &theFSS, fsRdWrPerm);
  559.                 if (err) break;
  560.  
  561.                 gPrintPage = mode;
  562.                     /* Open the window off-screen if we are printing. */
  563.                 if (err = AppNewWindow(frHndl, &docWindow))
  564.                     AppDisposeDocument(frHndl);
  565.                 else {
  566.                     if (gPrintPage) {
  567.                         err  = AppPrintDocument(frHndl, (mode == 2), (loop == 1));
  568.                         mode = 1;
  569.                         AppDisposeDocument(frHndl);
  570.                         DisposeAnyWindow(docWindow);
  571.                     }
  572.                 }
  573.                 gPrintPage = 0;
  574.             }
  575.         }
  576.     }
  577.     AppPrintDocument(nil, false, false);    /* Clean up after printing, if we did any. */
  578.  
  579.     err2 = AEDisposeDesc(&theDesc);
  580.     return(err ? err : err2);
  581. }
  582.  
  583.  
  584.  
  585.